package com.stars.common;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 
 * @author xiaowei
 * @date 2017年5月8日
 */
public class ObjectCopyUtils {

	public static final Logger LOGGER = LoggerFactory.getLogger(ObjectCopyUtils.class);

	public static boolean isCopy(String name, String[] excludes) {
		boolean flag = true;
		for (String fieldName : excludes) {
			if (name == fieldName) {
				flag = false;
				break;
			}
		}
		return flag;
	}

	/**
	 * 逐个遍历dest对象的属性，若如orig对象的属性名称一致，则复制orig的属性值给dest对象的属性值。忽略null值
	 * 
	 * @param orig
	 * @param dest
	 * @param <T>
	 * @return
	 */
	public static <T> T copyPropertiesIf(T orig, T dest) {
		return copyPropertiesIf(orig, dest, null, dest.getClass(), false);
	}

	/**
	 * 逐个遍历dest对象的属性，若如orig对象的属性名称一致，则复制orig的属性值给dest对象的属性值。
	 * 忽略null值和excludes中的属性名
	 * 
	 * @param orig
	 * @param dest
	 * @param excludes
	 * @param <T>
	 * @return
	 */
	public static <T> T copyPropertiesIf(T orig, T dest, String[] excludes) {
		return copyPropertiesIf(orig, dest, excludes, dest.getClass(), false);
	}

	/**
	 * 逐个遍历dest对象的属性，若如orig对象的属性名称一致，则复制orig的属性值给dest对象的属性值。包含null值
	 * 
	 * @param orig
	 * @param dest
	 * @param excludes
	 * @param <T>
	 * @return
	 */
	public static <T> T copyPropertiesIfIncludeNull(T orig, T dest, String[] excludes) {
		return copyPropertiesIf(orig, dest, excludes, dest.getClass(), true);
	}

	/**
	 * 从资源对象中复制属性值到目标对象中
	 * 
	 * @param orig
	 *        资源对象
	 * @param dest
	 *        目标对象
	 * @param clazz
	 *        源对象类
	 * @param excludes
	 *        排除字段
	 * @return
	 */
	public static <T> T copyPropertiesIf(T orig, T dest, String[] excludes, Class<?> clazz, Boolean includeNull) {
		if (orig == null || dest == null) {
			return null;
		}
		if (!clazz.isAssignableFrom(dest.getClass())) {
			return null;
		}
		Class<? extends Object> origClass = orig.getClass();
		Field origField;
		Field[] fields = clazz.getDeclaredFields();
		Object type;
		Object value;
		boolean flag = true;

		for (Field field : fields) {
			try {
				if (field.getName() == "serialVersionUID") {
					continue;
				}
				if (excludes != null) {
					flag = isCopy(field.getName(), excludes);

					if (!flag) {
						continue;
					}
				}

				field.setAccessible(true);
				type = field.getType();

				origField = findField(origClass, field);
				if (origField == null) {
					continue;
				}
				origField.setAccessible(true);
				value = origField.get(orig);

				if (!java.lang.reflect.Modifier.isFinal(field.getModifiers())) {
					if (value != null) {
						if ("".equals(value)) {
							field.set(dest, null);
							continue;
						}

						if (type.equals(origField.getType())) {
							field.set(dest, value);
							continue;
						}
						// 日期类型转换
						if (type.equals(Date.class)) {
							value = toDate(value);
						}
						// BigDecimal转换
						if (type.equals(BigDecimal.class)) {
							value = toBigDecimal(value);
						}
						// Integer转换
						if (type.equals(Integer.class)) {
							value = Integer.parseInt((String) value);
						}

						field.set(dest, value);

					}
					if (includeNull) {
						field.set(dest, null);
					}
				}
				field.setAccessible(false);
				origField.setAccessible(false);
			} catch (Exception e) {

			}
		}

		if (clazz.getSuperclass() == null) {
			return dest;
		}

		return copyPropertiesIf(orig, dest, excludes, clazz.getSuperclass(), includeNull);
	}

	public static Field findField(Class<?> origClass, Field field) {
		try {
			return origClass.getDeclaredField(field.getName());
		} catch (NoSuchFieldException e) {
			if (origClass.getSuperclass() != null) {
				return findField(origClass.getSuperclass(), field);
			}
			return null;
		}

	}

	public static BigDecimal toBigDecimal(Object value) {
		BigDecimal bd = new BigDecimal((String) value);
		return bd;
	}

	public static Date toDate(Object value) {
		SimpleDateFormat sdf;
		Date date = null;
		boolean flag = true;
		sdf = new SimpleDateFormat(MyDateUtils.YYYY_MM_DD_HH_MM_SS);
		try {
			date = sdf.parse((String) value);
			flag = true;
		} catch (Exception e) {
			flag = false;
		}
		if (!flag) {
			sdf = new SimpleDateFormat(MyDateUtils.YYYY_MM_DD_);
			try {
				date = sdf.parse((String) value);
				flag = true;
			} catch (ParseException e) {
				flag = false;
			}
		}

		if (!flag) {
			sdf = new SimpleDateFormat(MyDateUtils.YYYY_MM_DD_HH_MM_SS_SSS);
			try {
				date = sdf.parse((String) value);
				flag = true;
			} catch (ParseException e) {
				flag = false;
			}
		}
		if (!flag) {
			sdf = new SimpleDateFormat(MyDateUtils.YYYY_MM_DD_HH_MM_SS);
			try {
				date = sdf.parse((String) value);
				flag = true;
			} catch (ParseException e) {
				flag = false;
			}
		}
		if (!flag) {
			sdf = new SimpleDateFormat(MyDateUtils.YYYY_MM_DD);
			try {
				date = sdf.parse((String) value);
				flag = true;
			} catch (ParseException e) {
				flag = false;
			}
		}
		if (!flag) {
			sdf = new SimpleDateFormat(MyDateUtils.YYYY_MM_CN);
			try {
				date = sdf.parse((String) value);
				flag = true;
			} catch (ParseException e) {
				flag = false;
			}
		}

		if (!flag) {
			sdf = new SimpleDateFormat(MyDateUtils.timestampe());
			try {
				date = sdf.parse((String) value);
				flag = true;
			} catch (ParseException e) {
				flag = false;
			}
		}
		return date;
	}

	/**
	 * 复制对象属性（对象类型必须相同）
	 * 
	 * @param orig
	 *        资源对象
	 * @param dest
	 *        目标对象
	 * @param clazz
	 *        源对象类
	 * @param ignoreNull
	 *        是否忽略空（true:忽略，false：不忽略）
	 * @return
	 */
	public static <T> T copyProperties(T orig, T dest, Class<?> clazz, boolean ignoreNull) {
		if (orig == null || dest == null) {
			return null;
		}
		if (!clazz.isAssignableFrom(orig.getClass())) {
			return null;
		}
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			try {
				field.setAccessible(true);
				Object value = field.get(orig);
				if (!java.lang.reflect.Modifier.isFinal(field.getModifiers())) {
					if (!(ignoreNull && value == null)) {
						field.set(dest, value);
					}
				}
				field.setAccessible(false);
			} catch (Exception e) {}
		}

		if (clazz.getSuperclass() == Object.class) {
			return dest;
		}

		return copyProperties(orig, dest, clazz.getSuperclass(), ignoreNull);
	}

	/**
	 * 复制对象属性（对象类型必须相同）
	 * 
	 * @param orig
	 *        资源对象
	 * @param dest
	 *        目标对象
	 * @param ignoreNull
	 *        是否忽略空（true:忽略，false：不忽略）
	 */
	public static <T> T copyProperties(T orig, T dest, boolean ignoreNull) {
		if (orig == null || dest == null) {
			return null;
		}
		return copyProperties(orig, dest, orig.getClass(), ignoreNull);
	}

	/**
	 * 复制对象
	 * 
	 * @param src
	 *        资源对象
	 * @return 新对象
	 */
	@SuppressWarnings("unchecked")
	public static <T> T clone(T src) {
		if (src == null) {
			return null;
		}
		T newObject = null;
		try {
			newObject = (T) src.getClass().newInstance();
		} catch (Exception e) {
			LOGGER.error(e.getClass().getName(), e);
		}

		return copyProperties(src, newObject, false);
	}
}
